多线程(看这一篇就够了,超详细,满满的干货)

您所在的位置:网站首页 操作系统 线程同步 多线程(看这一篇就够了,超详细,满满的干货)

多线程(看这一篇就够了,超详细,满满的干货)

2024-07-12 19:35| 来源: 网络整理| 查看: 265

多线程 一.认识线程(Thread)1. 1) 线程是什么1. 2) 为啥要有线程1.3) 进程和线程的区别标题1.4) Java的线程和操作系统线程的关系 二.创建线程方法1:继承Thread类方法2:实现Runnable接口方法3:匿名内部类创建Thread子类对象标题方法4:匿名内部类创建Runnable子类对象方法5:lambda表达式创建Runnable子类对象 三.Thread类及其方法3.1Thread的常见构造方法3.2Thread的几个常见属性3.3获取当前线程引用3.4休眠当前线程 四:线程的状态4.1线程的所有状态4.2线程状态和状态转移的意义4.3观察线程的状态和转移示例1:示例2: 五:多线程带来的的风险-线程安全(重点)5.1线程安全的概念5.2线程不安全的原因5.3线程的几大特性5.3.1:原子性5.3.2:可见性5.3.3:指令重排序 在这里插入图片描述

​​在这里插入图片描述 在这里插入图片描述

​​​​​​

一.认识线程(Thread) 1. 1) 线程是什么

⼀个线程就是⼀个 “执行流”. 每个线程之间都可以按照顺序执行自己的代码. 多个线程之间 “同时” 执行着多份代码,main()⼀般被称为主线程(Main Thread)。

1. 2) 为啥要有线程

首先, “并发编程” 成为 “刚需”.

单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU. 而并发编程能更充分利用多核 CPU 资源.

有些任务场景需要 “等待 IO”, 为了让等待 IO 的时间能够去做⼀些其他的工作, 也需要用到并发编程. 其次, 虽然多进程也能实现 并发编程, 但是线程比进程更轻量.

创建线程比创建进程更快.

销毁线程比销毁进程更快.

调度线程比调度进程更快.

最后, 线程虽然比进程轻量, 但是人们还不满足, 于是又有了 “线程池”(ThreadPool) 和 “协程”(Coroutine) 关于线程池我们后面再介绍. 关于协程的话题我们此处暂时不做过多讨论.

1.3) 进程和线程的区别 进程是包含线程的. 每个进程至少有⼀个线程存在,即主线程。进程和进程之间不共享内存空间. 同⼀个进程的线程之间共享同⼀个内存空间.进程是系统分配资源的最小单位,线程是系统调度的最小单位。⼀个进程挂了⼀般不会影响到其他进程. 但是⼀个线程挂了, 可能把同进程内的其他线程⼀起带走(整 个进程崩溃) 标题1.4) Java的线程和操作系统线程的关系

线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对用户层提供了⼀些API供用户使用(例如Linux的pthread库) 例如:Java标准库Thread的类可以视为是对操作系统提供的API进行了进⼀步的抽象和封装.

二.创建线程 方法1:继承Thread类

继承Thread来创建⼀个线程类,直接使用this就表示当前线程对象的引用

class MyThread extends Thread { @Override public void run() { System.out.println("这⾥是线程运⾏的代码"); } } public class Test { public static void main(String[] args) { MyThread t = new MyThread(); t.start(); } } 方法2:实现Runnable接口

实现Runnable接口,this表示的是 MyRunnable 的引用.需要使用Thread.currentThread()

class MyRunnable implements Runnable { @Override public void run() { System.out.println("这⾥是线程运⾏的代码"); } } public class Test { public static void main(String[] args) { Thread t = new Thread(new MyRunnable()); t.start(); } } 方法3:匿名内部类创建Thread子类对象 public class Test { public static void main(String[] args) { // 使⽤匿名类创建 Thread ⼦类对象 Thread t1 = new Thread() { @Override public void run() { System.out.println("使⽤匿名类创建 Thread ⼦类对象"); } }; } } 标题方法4:匿名内部类创建Runnable子类对象 public class Test { public static void main(String[] args) { // 使⽤匿名类创建 Runnable ⼦类对象 Thread t2 = new Thread(new Runnable() { @Override public void run() { System.out.println("使⽤匿名类创建 Runnable ⼦类对象"); } }); } } 方法5:lambda表达式创建Runnable子类对象 public class Test { public static void main(String[] args) { // 使⽤匿名类创建 Runnable ⼦类对象 // 使⽤ lambda 表达式创建 Runnable ⼦类对象 Thread t3 = new Thread(() -> System.out.println("使⽤匿名类创建 Thread ⼦类对象")); Thread t4 = new Thread(() -> { System.out.println("使⽤匿名类创建 Thread ⼦类对象"); }); } } 三.Thread类及其方法

Thread 类是 JVM 用来管理线程的⼀个类,换句话说,每个线程都有⼀个唯⼀的 Thread 对象与之关联。而Thread 类的对象就是用来描述⼀个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

3.1Thread的常见构造方法

在这里插入图片描述

Thread t1 = new Thread(); Thread t2 = new Thread(new MyRunnable()); Thread t3 = new Thread("这是我的名字"); Thread t4 = new Thread(new MyRunnable(), "这是我的名字"); 3.2Thread的几个常见属性

在这里插入图片描述

ID是线程的唯⼀标识,不同线程不会重复

名称是各种调试工具用到

状态表示线程当前所处的⼀个情况,下面我们会进⼀步说明

优先级高的线程理论上来说更容易被调度到

关于后台线程,需要记住⼀点:JVM会在⼀个进程的所有非后台线程结束后,才会结束运行。 是否存活,即简单的理解,为run方法是否运行结束了

public class Test { public static void main(String[] args) { Thread thread = new Thread(() -> { for (int i = 0; i { for (int i = 0; i 3->2的方式执行,也是没问 题,可以少跑⼀次前台。这种叫做指令重排序 编译器对于指令重排序的前提是"保持逻辑不发生变化".这⼀点在单线程环境下比较容易判断,但是 在多线程环境下就没那么容易了,多线程的代码执行复杂程度更高,编译器很难在编译阶段对代码的 执行效果进行预测,因此激进的重排序很容易导致优化后的逻辑和之前不等价. 重排序是⼀个比较复杂的话题,涉及到CPU以及编译器的⼀些底层工作原理,此处不做过多讨论

在这里插入图片描述 如果觉得文章不错,期待你的一键三连哦,你个鼓励是我创作的动力之源,让我们一起加油,顶峰相见*!!!💓 💓 💓*



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3